<?php
/**
 * Created by PhpStorm.
 * User: xing.chen
 * Date: 2017/9/14
 * Time: 12:27
 */
namespace xing\upload;

use xing\helper\resource\HttpHelper;
use xing\upload\sdk\AliOssClient;
use Yii;
use OSS\OssClient;
use xing\upload\core\BaseUpload;

/**
 * Class UploadAli
 * @package xing\upload
 *
 * @property \OSS\OssClient $drive
 */
class UploadAli extends BaseUpload implements \xing\upload\core\UploadInterface
{

    public $drive;

    public $config;

    public function getSignature($file, $fileType, $maxLength = 26214400)
    {
        $id = $this->config['OSS_ACCESS_ID'];          // 请填写你的AccessKeyId。
        $key = $this->config['OSS_ACCESS_KEY'];     // 请填写你的AccessKeySecret。
        // $host的格式为 bucketname.endpoint，请替换为你的真实信息。
        $host = $this->config['OSS_ENDPOINT'];
        // $callbackUrl为上传回调服务器的URL，请将下面的IP和Port配置为您自己的真实URL信息。
        $callbackUrl = 'http://公网ip地址:8080/aliyun-oss-appserver-php/php/callback.php';

        $callback_param = array('callbackUrl'=>$callbackUrl,
            'callbackBody'=>'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',  'callbackBodyType'=>"application/x-www-form-urlencoded");
        $callback_string = json_encode($callback_param);

        $base64_callback_body = base64_encode($callback_string);
        $end = time() + 600;
        $expiration = $this->gmtIso8601($end);



        $conditions = [['starts-with', '$key', dirname($file) . '/']];
        if (!empty($maxLength)) $conditions[] = ['content-length-range', 0, $maxLength]; //最大文件大小
        if (!empty($fileType)) $conditions[] = ["in", '$content-type', [$fileType]];
        // 表示用户上传的数据，必须是以$dir开始，不然上传会失败，这一步不是必须项，只是为了安全起见，防止用户通过policy上传到别人的目录。

        $policy = json_encode(['expiration' => $expiration, 'conditions' => $conditions,]);
        $base64_policy = base64_encode($policy);
        $signature = base64_encode(hash_hmac('sha1', $base64_policy, $key, true));

        $response = array();
        $response['accessid'] = $id;
        $response['host'] = $host;
        $response['policy'] = $base64_policy;
        $response['signature'] = $signature;
        $response['expire'] = $end;
        $response['callback'] = $base64_callback_body;
        $response['dir'] = dirname($file) . '/';  // 这个参数是设置用户上传文件时指定的前缀。
        $response['file'] = $file;
        return $response;
    }
    private function gmtIso8601($time)
    {
        return (new \DateTime(null, new \DateTimeZone('UTC')))->setTimestamp($time)->format('Y-m-d\TH:i:s\Z');
    }
    public function getRestParams($method, $module, $file, $fileType = '', $size = '')
    {

        $drive = new AliOssClient(
            $this->config['OSS_ACCESS_ID'],
            $this->config['OSS_ACCESS_KEY'],
            $this->config['OSS_ENDPOINT']
        );
        $extension = strpos($file, '.')
            ? preg_replace('/(.*)\./', '',$file)
            : preg_replace('/(.*)\//', '',$fileType);
        $saveFilename = $this->getRelativePath($this::createFilename() . '.' . $extension, $module);
        $object = $this->relativePath . $saveFilename;
        $options = ['bucket' => $this->config['UploadBucket'], 'VERB' => $method, 'object' => $object, 'Content-Type' => $fileType];
        if (!empty($size)) $options['Content-Length'] = $size;
        return $drive->getRestParams($options);
    }

    public function upload($fieldName, $module = '')
    {
        if (!isset($_FILES[$fieldName])) throw new \Exception('请上传文件');
        $info = isset($_FILES[$fieldName]) ? $_FILES[$fieldName] : null;
        if (empty($info)) throw new \Exception('没有获取到文件');

        $file = $info['tmp_name'];
        $fileType = $info['type'] ?? static::getFileType($file);
        $extension = $this->fileTypes[$fileType] ?? preg_replace('/(.*)\./', '', $info['name']) ?? '';
        $saveFilename = $this->getRelativePath($this::createFilename() . '.' . $extension, $module);
        $r = $this->drive->uploadFile($this->config['UploadBucket'], $this->relativePath . $saveFilename, $file);
        if (!isset($r['oss-request-url']) || empty($r['oss-request-url'])) throw new \Exception('上传至云端失败');

        return [
            'url' => $this->getFileUrl($saveFilename),
            'saveUrl' => $saveFilename,
        ];
    }

    /**
     * 上传网络文件
     * @param $url
     * @param string $module
     * @return array
     * @throws \Exception
     */
    public function uploadUrl($url, $module = '')
    {
//        $info = get_headers($url);
        $mine = HttpHelper::getImageType($url);
        $base64 = static::base64EncodeImage($url, $mine);
        return $this->uploadBase64($base64, $module);
    }

    public function uploadBase64(& $base64, $module = '')
    {
        $newFilename = $this->createBase64Filename($base64);
        #  相对路径
        $saveFilename = $this->getRelativePath($newFilename, $module);
        $r = $this->drive->putObject($this->config['UploadBucket'], $this->relativePath . $saveFilename,  $this->getBase64Decode($base64));
        if (!isset($r['oss-request-url']) || empty($r['oss-request-url'])) throw new \Exception('上传至云端失败');
        return [
            'url' => $this->getFileUrl($saveFilename),
            'saveUrl' => $saveFilename,
        ];
    }

    public function delete($file)
    {
        return $this->drive->deleteObject($this->config['UploadBucket'], $file);
    }

    /**
     * @param $config
     * @return $this
     */
    public function config($config)
    {
        parent::config($config);
        $this->config = $config;

        $this->drive = new OssClient(
            $config['OSS_ACCESS_ID'],
            $config['OSS_ACCESS_KEY'],
            $config['OSS_ENDPOINT']
        );
        return $this;
    }
}
